package org.nimi317.web_gis.interceptor;

import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.TableNameParser;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.nimi317.web_gis.division.DivisionInterface;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

import static org.nimi317.web_gis.data.AreaCodeList.getStrategy;

/**
 * @author thunderobot
 * 分表
 */
@Slf4j
public class MybatisInterceptor implements InnerInterceptor {

    private void extracted(PluginUtils.MPBoundSql boundSql) {
        String sql = boundSql.sql();
        TableNameParser tableNameParser = new TableNameParser(sql);
        /*
            当前的表名
         */
        List<TableNameParser.SqlToken> names = new ArrayList<>();
        tableNameParser.accept(names::add);
        /*
         * 获取分表策略
         */
        StringBuilder builder = new StringBuilder();
        int last = 0;
        for (TableNameParser.SqlToken name : names) {
            String value = name.getValue();
            DivisionInterface strategy = getStrategy(value);
            String s = ObjectUtils.isEmpty(strategy) ? value : strategy.divisionTableName(value, sql, name,boundSql);
            int start = name.getStart();
            if (start != last) {
                builder.append(sql, last, start);
                builder.append(s != null ? s : value);
            }
            last = name.getEnd();
        }
        if (last != sql.length()) {
            builder.append(sql.substring(last));
        }
        String string = builder.toString();
        boundSql.sql(string);
    }

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = mpSh.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct == SqlCommandType.SELECT || sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            if (InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) {
                return;
            }
            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
            this.extracted(mpBs);
        }
    }
}
